'''
This is a ping tool for multiple IP addresses.
Author: <icsteam.cn>
Date: 2024-04-15
Update: 2024-11-02
Version: 2.1.0
Statement: my code is based on ping3,rich package and python 3.11.4,Thanks to them. 
'''
import time,os
from ping3 import ping
import threading as thd
from rich import print as rprint
def sec_to_hms(seconds):
    hours = int(seconds // 3600)
    minutes = int((seconds % 3600) // 60)
    seconds = int(seconds % 60)
    return hours, minutes, seconds
def file_exists(file_path):
    title = '''
    --------------------
    This is a ping tool for multiple IP addresses.
    Author: <icsteam.cn>
    Date: 2024-04-15
    Update: 2024-11-02
    Version: 2.1.0
    Statement: my code is based on ping3,rich package and python 3.11.4,Thanks to them. 
    --------------------
    '''
    if not os.path.isfile(file_path):
        with open(file_path,'w') as f:
            f.write(title+'\n')
def folder_exists(folder_path):
    if not os.path.exists(folder_path):
        os.makedirs(folder_path)
# 打印信息并记录
def info(nfile,mode,name,info):
    '''
    nfile: 日志文件名
    mode: 日志级别，0为错误，1为信息
    name: 日志名称
    info: 日志内容
    '''
    #获取当前格式化时间
    def NowTime(mode=0):
        # global now_time,now_time1
        temp_nt=time.strftime('%Y-%m-%d %H:%M:%S',time.localtime())         #格式化时间
        temp_nt1=time.strftime('%Y%m%d_%H%M',time.localtime())
        if mode == 0 :
            now_time=temp_nt  
        elif mode ==1 :
            now_time=temp_nt1
        else:
            now_time=None
        return now_time
    #记录日志
    def logger(nfile,text):
        with open(nfile,'a') as f:
            f.write(f'{text}\n')
    nt=NowTime()
    if mode == 0 :
        pt= f'[{nt}] [red][E][/red] [#FFEDED]{name}: [/#FFEDED]{info}'
        text= f'[{nt}] [E] {name}: {info}'
    elif mode ==1 :
        pt= f'[{nt}] [green][I][/green] [#FFEDED]{name}: [/#FFEDED]{info}'
        text= f'[{nt}] [I] {name}: {info}'
    elif mode ==2 :
        text=f'[{nt}] [I] {name}: {info}'
    else:
        pt= f'[{nt}] {name}: {info}'
        text= f'[{nt}] {name}: {info}'
    logger(nfile,text)
    if mode !=2:
        rprint(pt+'\n',end='')
# 读配置文件，输出字典
def file_read(text,code='gbk'): 
    '''
    读取文件，文件每行格式为：
    名称=内容
    返回一个字典
    ---
    text: 文件名
    code: 文件编码
    '''
    dic={}
    # 去字符串空格
    def clear_space(s):
        return s.replace(' ','')
    with open(text,'r',encoding=code) as f :
        data=f.read()
        data=data.split('\n')
        tmp=[]
        specil = 0
        for row in data:
            try:
                if row[0] !='#' and len(row)!=0:
                    if ('[' not in row or ('[' in row and ']' in row) ) and specil == 0:
                        if '#' in row:
                            row=row.split('#')[0]
                        row=row.split('=')
                        key = clear_space(row[0])
                        value = clear_space(row[1])
                        dic[key]=value
                    else:
                        specil =1
                        pass
                if len(row)!=0 and specil == 1:
                    if '#' in row:
                            row=row.split('#')[0]
                    tmp.append(row)
                    if ']' in row:
                        specil = 0
                        tmp=''.join(tmp)
                        tmp=tmp.replace(' ','')
                        tmp = (tmp.split('='))
                        key = clear_space(tmp[0])
                        value = clear_space(tmp[1])
                        dic[key]=value
                        tmp=[]
            except Exception as e:
                pass
    return dic 
# ping方法
def fb_ping(client,freq,debug):
    '''
    client: 客户端列表，格式为[ip地址，超时标识，连接标识，超时时的当前时间，首次扫描，累加器]
    freq: 循环ping频率
    debug: '1'为调试模式
    '''
    tmp_freq=1          #循环间隔初始化
    ip=0                #命名切片，ip地址
    time_out_en=1       #命名切片，超时
    connect_en=2        #命名切片，正常连接
    time_out_start=3    #命名切片，超时时的当前时间
    first_scan=4        #命名切片，首次扫描
    ac0=5               #命名切片，累加器
    Tag_errEn=0         #错误标识
    # 格式化IP地址长度
    def strutIP(IP):
        tmpList = IP.split('.')
        newIp = [j if len(j)==3 else '0'*(3-len(j))+j for j in tmpList]
        return '.'.join(newIp)
    while 1:
        try:
            # ping操作返回状态，status_ping
            status_ping=ping(client[ip],timeout=1,unit='ms',size=32)
            Tag_errEn = 0
        except Exception as err:
            if Tag_errEn == 0:
                info(f'./logs/log.txt',0,client[ip],err)
                Tag_errEn = 1
        # 调试，单独记录
        if debug =='1':
            info(f'./logs/debug/{client[ip]}_debug.txt',2,client[ip],status_ping)
        # 超时
        if (status_ping==False or status_ping==None) and type(status_ping)!= float:
            if client[time_out_en]==1 :
                client[connect_en]=0
            else:
                client[ac0]+=1
                if client[ac0]>=3 :
                    info('./logs/log.txt',0,strutIP(client[ip]),f'ping超时！')
                    client[time_out_en]=1
                    client[connect_en]=0
                if client[ac0] == 1 :
                    client[time_out_start]=time.time()
            tmp_freq=2
        else: 
            tmp_freq=freq   #正常连接使用配置文件的ping频率
            client[ac0]=0   #累加器
            if client[connect_en]==1 :
                client[time_out_en]=0
            else:
                if client[first_scan]==1:
                    end_time=time.time()
                    usage_time=round(end_time-client[time_out_start],1)
                else:
                    usage_time=0
                usage_time = sec_to_hms(usage_time)
                usage_time = f'{usage_time[0]}小时{usage_time[1]}分{usage_time[2]}秒'
                info('./logs/log.txt',1,strutIP(client[ip]),f'ping成功！距上次超时{usage_time}')
                client[connect_en]=1
                client[time_out_en]=0
        client[first_scan]=1
        time.sleep(tmp_freq)
def client(ipList,freq,debug):
    '''
    iplist: ip列表
    freq: 循环ping频率
    debug: '1'为调试模式
    '''
    pinglist=ipList      # ip列表
    temp_pinglist=[]    # 临时列表
    thd_list=[]         # 线程列表
    for i in pinglist :
        temp_pinglist.append([i,0,0,0,0,0]) # [ip地址，超时标识，连接标识，超时时的当前时间，首次扫描，累加器]
        thd_list.append('')
    for i in range(len(temp_pinglist)):
        # 取元素开线程
        thd_list[i]=thd.Thread(target=fb_ping,args=(temp_pinglist[i],freq,debug))
        thd_list[i].daemon=True
        thd_list[i].start()
        time.sleep(0.1)
    while 1:
        # 主线程，该线程结束子线程也跟着结束
        time.sleep(30)
if __name__ == '__main__' :
    title='''
                  '########::'####:'##::: ##::'######::::::'########::'#######:::'#######::'##:::::::
                   ##.... ##:. ##:: ###:: ##:'##... ##:::::... ##..::'##.... ##:'##.... ##: ##:::::::
                   ##:::: ##:: ##:: ####: ##: ##:::..::::::::: ##:::: ##:::: ##: ##:::: ##: ##:::::::
                   ########::: ##:: ## ## ##: ##::'####::::::: ##:::: ##:::: ##: ##:::: ##: ##:::::::
                   ##.....:::: ##:: ##. ####: ##::: ##:::::::: ##:::: ##:::: ##: ##:::: ##: ##:::::::
                   ##::::::::: ##:: ##:. ###: ##::: ##:::::::: ##:::: ##:::: ##: ##:::: ##: ##:::::::
                   ##::::::::'####: ##::. ##:. ######::::::::: ##::::. #######::. #######:: ########:
                  ..:::::::::....::..::::..:::......::::::::::..::::::.......::::.......:::........::
                '''
    print(title)
    my_info=rprint('作者：工控万金油\n版本：2.1.0\n首版日期：2024年04月15日\n更新日期：2024年11月02日\n[#EE8AF8]声明：我的代码是基于ping3、rich包和python 3.11.4的，感谢他们。[/#EE8AF8]\n',end='')
    folder_exists('logs')
    file_exists('./logs/log.txt')
    folder_exists('./logs/debug')
    try:
        config=file_read('config.conf','utf-8')  # 读取配置文件
    except Exception as err:
        info('./logs/log.txt',0,'读取配置文件出错',err)
    try:
        debug=config['debug']                   # 调试模式值
        freq=eval(config['pingSpace'])          #ping间隔
        ip_list=eval(config['IP'])              #ip列表
        tmpIpList=[i.split('.') for i in ip_list]    #ip地址拆分为列表
        # ip最右一字节存在‘-’，则为连续ip段，需要拆分
        def check_ipList(InIpList):
            new_ip_list=[]
            for ipList in InIpList:
                if '-' in (ipList[-1]):
                    start,end = ipList[-1].split('-')
                    for i in range(int(start),int(end)+1):
                        ipList[-1]=str(i)
                        new_ip_list.append('.'.join(ipList))
                else:
                    new_ip_list.append('.'.join(ipList))
            return new_ip_list
        new_ip_list=check_ipList(tmpIpList)
        printConf = f'开始扫描的ip有：{new_ip_list}，共{len(new_ip_list)}个IP地址，ping间隔{freq}秒'
        rprint(printConf)
    except Exception as err:
        info('./logs/log.txt',0,'检查配置参数是否正确',err)
        os.system('pause')
    
    with open('./logs/log.txt','a') as f:
        f.write(f'{printConf}\n')
    client(new_ip_list,freq,debug)


    